import json
from typing import Any

from dotenv import load_dotenv
from fastmcp import FastMCP
from fastmcp.prompts.prompt import PromptMessage, TextContent
import os
import requests

# 提前安装pip3 install fastmcp依赖

# 初始化 MCP 服务器
mcp = FastMCP("MyMcpServer")


# 定义一个的资源，资源可以是动态数据模板，静态资源等，获取资源是一个只读的操作，协议名自己定义，传参为restful风格，client调用时指明协议名和uri
# 函数体一般为获取资源的逻辑，不推荐做广义的写操作，原则上要求调用是幂等的，且自带缓存功能
# mcp.resource()的uri支持固定部分和动态参数(PathVariables)用{}表示,但不支持查询参数, 且uri(协议+path)需唯一，避免出现动态参数模板占位冲突的情况
# 如@mcp.resource("welcome://version1/{name}/{language}")会与下面的冲突
@mcp.resource("welcome://version1/{language}/{name}")
def welcome(language,name):
    if language == 'zh':
        return f"你好，{name}！"
    elif language == 'en':
        return f"Hello, {name}!"

@mcp.resource("welcome://version2/{language}/{name}")
def welcome(language,name):
    if language == 'zh':
        return f"你好2，{name}！"
    elif language == 'en':
        return f"Hello2, {name}!"


# 定义一个提示模板，用于生成与llm交互的提示文本，便于构建标准化消息和对话内容
# 可以把一些通用的对话场景抽象成提示模板，客户端调用时指明name和参数
@mcp.prompt()
def generate_code_request(language, task):
    content = f"请写一个用{language}语言完成以下任务的函数：{task}"
    return PromptMessage(role="user", content=TextContent(type="text", text=content))




def fetch_weather(city: str) -> dict[str, Any] | None:
    """
    获取天气API
    :param city: 城市名称（如 上海）
    :return: 天气数据字典；若出错返回包含 error 信息的字典
    """
    # Step 1.构建请求
    url = "https://getweather.api.bdymkt.com/lundear/weather1d"

    # Step 2.设置查询参数
    params = {
        "areaCn": city,
    }

    # 添加header
    headers = {
        "X-Bce-Signature": f"AppCode/{os.getenv('BAIDU_YUN_API_APP_CODE')}"
    }

    # Step 3.发送GET请求
    response = requests.get(url, params=params, headers=headers)

    # Step 4.解析响应
    return response.json()


def format_weather(data: dict[str, Any] | str) -> str:
    """
    将天气数据格式化为易读文本。
    :param data: 天气数据（可以是字典或 JSON 字符串）
    :return: 格式化后的天气信息字符串
    """
    # 如果传入的是字符串，则先转换为字典
    if isinstance(data, str):
        try:
            data = json.loads(data)
        except Exception as e:
            return f"无法解析天气数据: {e}"

    # 如果数据中包含错误信息，直接返回错误提示
    if "error" in data:
        return f"⚠️ {data['error']}"

    # 提取数据时做容错处理
    city = data.get("data").get("cityInfo").get("areaCn", "未知")
    country = data.get("data").get("cityInfo").get("nationCn","未知")
    temp = data.get("data").get("now").get("temp","N/A")
    humidity = data.get("data").get("now").get("sd","N/A")
    wind_speed = data.get("data").get("now").get("wse","N/A")
    description = data.get("data").get("now").get("weather","未知")

    return (
        f"🌍 {city}, {country}\n"
        f"🌡 温度: {temp}°C\n"
        f"💧 湿度: {humidity}\n"
        f"🌬 风速: {wind_speed} \n"
        f"🌤 天气: {description}\n"
    )

# 定义一个可执行的操作，name默认为函数名，client调用时指明name和参数，也是提供给agent调用的工具，需要写多行注释作为agent调用时的prompt参考
# mcp.tool()不支持可变参数
@mcp.tool()
def add(a, b):
    """
    两数相加
    :param a: 第一个加数
    :param b: 第二个加数
    :return: 两数之和
    """
    result = a + b
    print(f"MCP Server: add result {result}")
    return result

@mcp.tool()
def query_weather(city: str) -> str:
    """
    输入指定城市的中文名称，返回今日天气查询结果。
    :param city: 城市名称（需使用中文，如：上海）
    :return: 格式化后的天气信息
    """
    data = fetch_weather(city)
    return format_weather(data)

@mcp.tool()
def write_file(content):
    """
    将指定内容写入本地文件。
    :param content: 必要参数，字符串类型，用于表示需要写入文档的具体内容。
    :return：是否成功写入
    """
    with open("output.txt", "w", encoding="utf-8") as f:
        f.write(content)

    return "已成功写入本地文件。"


if __name__ == '__main__':
    load_dotenv(override=True)

    # 测试方法
    # result = fetch_weather('上海')
    # formated = format_weather(result)

    print("Starting MCP HTTP server on port 8080...")
    mcp.run(
        transport="http",  # HTTP 传输协议，别名也是 "streamable-http"
        host="0.0.0.0",  # 监听地址，0.0.0.0 表示所有网卡
        port=8080  # 指定监听端口
    )

